package workcode

import (
	"encoding/binary"
	"fmt"
	"inkjet168x-sdk-go/sdk/protocol/common"
)

// Protocol 命令包协议实现
type Protocol struct {
	// 协议头部
	StartBytes   [4]uint8  // 起始位: 0x5A 0x4B 0x43 0x54
	Sequence     uint16    // 序列号
	PacketType   uint8     // 数据包类型: 0x20
	PacketLength uint32    // 数据包长度
	
	// 命令数据包
	CommandCode  uint32    // 命令代码，uint32_t型，小端模式
	CommandParam uint32    // 命令参数，uint32_t型，小端模式
	Reserved     [4]uint8  // 保留字节，无需解析
	
	// 协议尾部
	Checksum     uint16    // CRC16校验和
	StopBytes    [2]uint8  // 停止位: 0x0D 0x0A
}

// NewProtocol 创建新的命令包协议实例
func NewProtocol() *Protocol {
	wp := &Protocol{
		StartBytes: [4]uint8{common.StartByte1, common.StartByte2, common.StartByte3, common.StartByte4},
		PacketType: 0x20, // 命令包协议类型
		StopBytes:  [2]uint8{common.StopByte1, common.StopByte2},
	}
	wp.updatePacketLength()
	return wp
}

// updatePacketLength 更新数据包长度
func (wp *Protocol) updatePacketLength() {
	// 计算数据包长度：固定12（命令代码+命令参数+保留字节）
	wp.PacketLength = 12
}

// SetSequence 设置序列号
func (wp *Protocol) SetSequence(sequence uint16) {
	wp.Sequence = sequence
}

// GetSequence 获取序列号
func (wp *Protocol) GetSequence() uint16 {
	return wp.Sequence
}

// SetCommandCode 设置命令代码
func (wp *Protocol) SetCommandCode(code uint32) {
	wp.CommandCode = code
}

// GetCommandCode 获取命令代码
func (wp *Protocol) GetCommandCode() uint32 {
	return wp.CommandCode
}

// SetCommandParam 设置命令参数
func (wp *Protocol) SetCommandParam(param uint32) {
	wp.CommandParam = param
}

// GetCommandParam 获取命令参数
func (wp *Protocol) GetCommandParam() uint32 {
	return wp.CommandParam
}

// GetType 获取协议类型
func (wp *Protocol) GetType() common.ProtocolType {
	return common.ProtocolType(wp.PacketType)
}

// Validate 验证协议数据
func (wp *Protocol) Validate() error {
	// 验证起始位
	if wp.StartBytes[0] != common.StartByte1 || 
	   wp.StartBytes[1] != common.StartByte2 || 
	   wp.StartBytes[2] != common.StartByte3 || 
	   wp.StartBytes[3] != common.StartByte4 {
		return fmt.Errorf("invalid start bytes")
	}
	
	// 验证停止位
	if wp.StopBytes[0] != common.StopByte1 || wp.StopBytes[1] != common.StopByte2 {
		return fmt.Errorf("invalid stop bytes")
	}
	
	// 验证数据包类型
	if wp.PacketType != 0x20 {
		return fmt.Errorf("invalid packet type: expected 0x20, got 0x%02X", wp.PacketType)
	}
	
	return nil
}

// Marshal 序列化协议为字节数组
func (wp *Protocol) Marshal() ([]byte, error) {
	if err := wp.Validate(); err != nil {
		return nil, fmt.Errorf("protocol validation failed: %w", err)
	}
	
	// 更新数据包长度
	wp.updatePacketLength()
	
	// 计算总长度
	totalLen := 27 // 命令包长度=序列号+数据包类型+数据包长度+命令代码+命令参数+保留字节+校验和+停止位
	buf := make([]byte, totalLen)
	offset := 0
	
	// 起始位
	copy(buf[offset:offset+4], wp.StartBytes[:])
	offset += 4
	
	// 序列号 (小端)
	binary.LittleEndian.PutUint16(buf[offset:offset+2], wp.Sequence)
	offset += 2
	
	// 数据包类型
	buf[offset] = wp.PacketType
	offset += 1
	
	// 数据包长度 (小端)
	binary.LittleEndian.PutUint32(buf[offset:offset+4], wp.PacketLength)
	offset += 4
	
	// 命令代码 (小端)
	binary.LittleEndian.PutUint32(buf[offset:offset+4], wp.CommandCode)
	offset += 4
	
	// 命令参数 (小端)
	binary.LittleEndian.PutUint32(buf[offset:offset+4], wp.CommandParam)
	offset += 4
	
	// 保留字节
	copy(buf[offset:offset+4], wp.Reserved[:])
	offset += 4
	
	// 计算校验和 (对数据包内容进行CRC16校验)
	dataForChecksum := buf[11:offset] // 从序列号到保留字节
	wp.Checksum = common.CalculateChecksum(dataForChecksum)
	
	// 校验和 (小端)
	binary.LittleEndian.PutUint16(buf[offset:offset+2], wp.Checksum)
	offset += 2
	
	// 停止位
	copy(buf[offset:offset+2], wp.StopBytes[:])
	
	return buf, nil
}

// Unmarshal 从字节数组反序列化协议
func (wp *Protocol) Unmarshal(data []byte) error {
	parsed, err := UnmarshalStatic(data)
	if err != nil {
		return err
	}
	*wp = *parsed
	return nil
}

// UnmarshalStatic 从字节数组反序列化协议（静态方法）
func UnmarshalStatic(data []byte) (*Protocol, error) {
	if len(data) < 25 { // 最小长度检查
		return nil, fmt.Errorf("data too short: expected at least 25 bytes, got %d", len(data))
	}
	
	wp := &Protocol{}
	offset := 0
	
	// 起始位
	copy(wp.StartBytes[:], data[offset:offset+4])
	offset += 4
	
	// 序列号
	wp.Sequence = binary.LittleEndian.Uint16(data[offset : offset+2])
	offset += 2
	
	// 数据包类型
	wp.PacketType = data[offset]
	offset += 1
	
	// 数据包长度
	wp.PacketLength = binary.LittleEndian.Uint32(data[offset : offset+4])
	offset += 4
	
	// 验证数据长度
	expectedLen := 4 + int(wp.PacketLength) + 2
	if len(data) < expectedLen {
		return nil, fmt.Errorf("data length mismatch: expected %d bytes, got %d", expectedLen, len(data))
	}
	
	// 命令代码
	wp.CommandCode = binary.LittleEndian.Uint32(data[offset : offset+4])
	offset += 4
	
	// 命令参数
	wp.CommandParam = binary.LittleEndian.Uint32(data[offset : offset+4])
	offset += 4
	
	// 保留字节
	copy(wp.Reserved[:], data[offset:offset+4])
	offset += 4
	
	// 校验和
	wp.Checksum = binary.LittleEndian.Uint16(data[offset : offset+2])
	offset += 2
	
	// 停止位
	copy(wp.StopBytes[:], data[offset:offset+2])
	
	// 验证协议
	if err := wp.Validate(); err != nil {
		return nil, err
	}
	
	// 验证校验和
	dataForChecksum := data[4 : offset-2] // 从序列号到保留字节
	expectedChecksum := common.CalculateChecksum(dataForChecksum)
	if wp.Checksum != expectedChecksum {
		return nil, fmt.Errorf("checksum mismatch: expected 0x%04X, got 0x%04X", expectedChecksum, wp.Checksum)
	}
	
	return wp, nil
}

// String 返回协议的字符串表示
func (wp *Protocol) String() string {
	return fmt.Sprintf("WorkcodeProtocol{Sequence: %d, CommandCode: 0x%08X, CommandParam: 0x%08X}", 
		wp.Sequence, wp.CommandCode, wp.CommandParam)
}